﻿/*
 * 打字机效果组件
 */
using System;
using UnityEngine;
using UnityEngine.UI;

public class TypewriterEffect : BaseMeshEffect
{
    enum WriteState
    {
        None,
        StartWrite,
        Writing
    }

    [SerializeField]
    private int textIndex;

    // 出字间隔
    [SerializeField]
    private float textInterval = 0.2f;

    private UIVertex vertex = new UIVertex();

    //记录刷新时间
    private float m_TimeCount = 0;

    private float m_charTime = 0;

    //是否开始显示打字
    private WriteState state = WriteState.None;

    ////每个字的出现间隔
    //private float m_TimeSpace = 0;

    //要显示的Text组件
    private Text m_Text;

    private int alphaIndex = 0;

    private float[] arrVertex;

    private int aniComplete = 0;
    private int m_charLen = 0;
    private int hasInit = 0;

    private Action m_Cb;
    private int vertexIndex;

    private int currentVertCount;

    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive())
        {
            return;
        }
        if (state == WriteState.None)
        {
            return;
        }
        currentVertCount = vh.currentIndexCount;
        m_charLen = vh.currentVertCount / 4;
        //文本长度
        if (state == WriteState.StartWrite)
        {
            for (var i = 0; i < vh.currentVertCount; i++)
            {
                vh.PopulateUIVertex(ref vertex, i);
                Color c = vertex.color;
                c.a = 0;
                vertex.color = c;
                vh.SetUIVertex(vertex, i);
            }
            state = WriteState.Writing;
            return;
        }
        int vCount = 4;
        vertexIndex = 0;
        int charLen = m_charLen;
        for (int i = 0; i < charLen; i++)
        {
            if (i >= arrVertex.Length())
                continue;

            float alpha = arrVertex[i];
            for (int j = 0; j < vCount; j++)
            {
                if (vertexIndex < vh.currentVertCount)
                {
                    vh.PopulateUIVertex(ref vertex, vertexIndex);
                    Color c = vertex.color;
                    c.a = alpha;
                    vertex.color = c;
                    vh.SetUIVertex(vertex, vertexIndex);
                }
                vertexIndex++;

            }
        }
        if (alphaIndex >= charLen && state > WriteState.None)
        {
            state = WriteState.None;
            aniComplete = 1;
        }

    }

    protected override void Awake()
    {
        m_Text = gameObject.GetComponent<Text>();
        textIndex = 0;
        m_Text.text = "";
    }

    protected override void Start()
    {

    }

    void Update()
    {
        if (state == WriteState.Writing)
        {
            if (hasInit == 0)
            {
                hasInit = 1;
                arrVertex = new float[m_charLen];
                for (int i = 0; i < m_charLen; i++)
                {
                    arrVertex[i] = 0;
                }
            }
            DoText();
            DoAlphaText();
        }
        if (aniComplete == 1)
        {
            aniComplete = 0;
            OnTextAniComplete();
        }
    }

    private void DoText()
    {
        int charLen = m_charLen;
        if (textIndex >= charLen)
        {
            return;
        }
        if (Time.unscaledTime - m_charTime > textInterval)
        {
            m_charTime = Time.unscaledTime;
            textIndex++;
        }
    }

    private void DoAlphaText()
    {
        if (Time.unscaledTime - m_TimeCount <= 0.01)
        {
            return;
        }
        m_TimeCount = Time.unscaledTime;
        int charLen = m_charLen;
        bool needModify = false;
        for (int i = alphaIndex; i < textIndex && i < charLen; i++)
        {
            float alpha = arrVertex[i];
            alpha += 0.1f;
            needModify = true;
            if (alpha >= 1)
            {
                alphaIndex++;
                alpha = 1;
            }
            arrVertex[i] = alpha;
        }
        if (needModify)
        {
            graphic.SetVerticesDirty();
        }
    }

    /// <summary>
    /// 播放打字效果
    /// </summary>
    /// <param name="contents"></param>
    public void PlayAni(string contents, float? interval = null, Action cb = null)
    {
        if (contents.IsNullOrEmpty())
        {
            return;
        }

        if (state > WriteState.None)
        {
            return;
        }

        if (m_Text==null)
        {
            return;
        }

        if (interval != null && interval is float)
            textInterval = (float)interval;
        else
            textInterval = 0.05f;
        m_Cb = cb;
  
        m_Text.text = contents;
        hasInit = 0;
        alphaIndex = 0;
        state = WriteState.StartWrite;
        textIndex = 0;
        graphic.SetVerticesDirty();
    }

    /// <summary>
    /// 停止打字
    /// </summary>
    public void StopAni()
    {
        state = WriteState.None;
    }

    public void ResultAni()
    {
        textIndex = m_charLen;
    }

    public bool IsComplete => textIndex >= m_charLen;

    public void ShowText()
    {
        if (hasInit == 0)
        {
            return;
        }
        alphaIndex = m_charLen;
        textIndex = m_charLen;
        for (int i = 0; i < m_charLen; i++)
        {
            arrVertex[i] = 1.0f;
        }
        graphic.SetVerticesDirty();
    }

    private void OnTextAniComplete()
    {
        m_Cb?.Invoke();
    }

    public int GetIndex()
    {
        return textIndex;
    }
}
